#pragma once

class M2BatchRender;

class M2InstanceLoader : public IGraphicsTask
{
	struct MdxInstanceData
	{
		D3DXMATRIX ModelMatrix;
		ui32 instanceID;
	};

	std::list<MdxInstanceData> mWaitingInstances;
	std::vector<MdxInstanceData> mActiveInstances;
	std::list<MdxInstanceData> mInvisInstances;
	std::list<ui32> mFreeID;
	ui32 mCurMaxID;
	Mutex mInstLock;
	M2BatchRender* mRenderer;
	bool mForceUpdate;
	bool isInstanceVisible(float x, float y, float z) {
		Vertex3F dir = sCamera.GetTargetPosition() - sCamera.GetCamPosition();
		auto cam = sCamera.GetCamPosition();

		Vertex3F destV(x - cam.x, y - cam.y, z - cam.z);
		float lens = destV.Length() * dir.Length();
		float scalar = dir.x * destV.x + dir.y * destV.y + dir.z * destV.z;
		float valCos = scalar / lens;
		float angle = (float)acos(valCos);
		float angleD = (angle * 180) / Math::PI;
		if(angleD > 60 || (destV.Length() > fogDistance + 0.16f * TILESIZE))
			return false;
		return true;
	}
public:
	M2InstanceLoader(M2BatchRender* render) : mRenderer(render), mCurMaxID(0), mForceUpdate(false) {
	}

	bool execute();
	void finish() { }

	ui32 pushInstance(const D3DXVECTOR3& position, float scale, const D3DXVECTOR3& rotation) {
		MdxInstanceData inst;
		D3DXMATRIX matTmp;
		D3DXMatrixScaling(&inst.ModelMatrix, scale, scale, scale);
		D3DXMatrixRotationYawPitchRoll(&matTmp, rotation.y, rotation.x - Math::PI / 2.0f, rotation.z - Math::PI / 2.0f);
		D3DXMatrixMultiply(&inst.ModelMatrix, &inst.ModelMatrix, &matTmp);
		D3DXMatrixTranslation(&matTmp, position.x, position.y, position.z);
		D3DXMatrixMultiply(&inst.ModelMatrix, &inst.ModelMatrix, &matTmp);

		mInstLock.Acquire();
		if(mFreeID.size()) {
			inst.instanceID = mFreeID.front();
			mFreeID.pop_front();
		} else {
			inst.instanceID = mCurMaxID++;
		}
		mWaitingInstances.push_back(inst);
		if(mWaitingInstances.size() == 1)
			sD3D.getTaskMgr().pushTask(this);
		mInstLock.Release();
		return inst.instanceID;
	}

	void removeInstance(ui32 id);
	void changeInstancePosition(ui32 id, const Vertex3F& position);
	bool isEmpty();

	void updateVisibility();
};